package com.hghivln.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.hghivln.constants.Constants;
import com.hghivln.mapper.SchedulingMapper;
import com.hghivln.mapper.UserMapper;
import com.hghivln.pojo.domain.Scheduling;
import com.hghivln.pojo.domain.User;
import com.hghivln.pojo.dto.SchedulingDto;
import com.hghivln.pojo.dto.SchedulingFormDto;
import com.hghivln.pojo.dto.SchedulingQueryDto;
import com.hghivln.pojo.vo.AjaxResult;
import com.hghivln.service.SchedulingService;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.Method;
import org.apache.dubbo.config.annotation.Service;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.*;

@Service(methods = {
        @Method(name = "saveScheduling",retries = 0,timeout = 6000)
})
public class SchedulingServiceImpl implements SchedulingService {

    @Autowired
    private SchedulingMapper schedulingMapper;

    @Autowired
    private UserMapper userMapper;

    /**
     * 1、得到 所在周的周一和周日 用来 删除原来的排班数据（所在周的周一和周日）
     * 2、得到用户名id 和 科室id， 如果数据库中存在就 删除全部数据
     * 3、初始化所在周 周一到周日的日期数据，再保存新的排班数据
     */
    @Override
    public AjaxResult saveScheduling(SchedulingFormDto schedulingFormDto) {
        if (CollectionUtil.isNotEmpty(schedulingFormDto.getData())) {
            DateTime dateTime = DateUtil.parse(schedulingFormDto.getBeginDate(), "yyyy-MM-dd");
            String beginTime = DateUtil.format(DateUtil.beginOfWeek(dateTime), "yyyy-MM-dd");
            String endTime = DateUtil.format(DateUtil.endOfWeek(dateTime), "yyyy-MM-dd");
            SchedulingFormDto.SchedulingData schedulingData = schedulingFormDto.getData().get(0);
            Long userId = schedulingData.getUserId();
            Long deptId = schedulingData.getDeptId();
            if (userId != null) {
                // 删除原来的排班数据
                QueryWrapper<Scheduling> qw = new QueryWrapper<>();
                qw.eq(Scheduling.COL_USER_ID, userId);
                qw.eq(Scheduling.COL_DEPT_ID, deptId);
                qw.between(Scheduling.COL_SCHEDULING_DAY, beginTime, endTime);
                schedulingMapper.delete(qw);
                // 初始化所在周 周一到周日的日期数据
                List<String> schedulingDays = initSchedulingDay(DateUtil.beginOfWeek(dateTime));
                // 保存新的排班数据
                for (SchedulingFormDto.SchedulingData datum : schedulingFormDto.getData()) {
                    Scheduling scheduling = null;
                    int i = 0; // 记录循环次数取日期值
                    for (String schedulingType : datum.getSchedulingType()) { // 排班类型（急诊/门诊）数据  schedulingType: ["1", "1", "2", "1", "1", "2", ""]
                        if (StringUtils.isNotBlank(schedulingType)) {
                            scheduling = new Scheduling(userId, deptId, schedulingDays.get(i), datum.getSubsectionType(), schedulingType, DateUtil.date(), schedulingFormDto.getSimpleUser().getUserName());
                            schedulingMapper.insert(scheduling);
                        }
                        i++;
                    }
                }
                return AjaxResult.success();
            }
        }
        return AjaxResult.fail("参数错误");
    }


    @Override
    public AjaxResult queryUsersNeedScheduling(SchedulingQueryDto schedulingQueryDto) {
        List<User> users = selectUsersNeedScheduling(schedulingQueryDto);
        return getSchedulingAjaxResult(schedulingQueryDto, users);
    }

    public List<User> selectUsersNeedScheduling(SchedulingQueryDto schedulingQueryDto) {
        QueryWrapper<User> qw = new QueryWrapper<>();
        qw.eq(schedulingQueryDto.getUserId() != null, Scheduling.COL_USER_ID, schedulingQueryDto.getUserId());
        qw.eq(schedulingQueryDto.getDeptId() != null, Scheduling.COL_DEPT_ID, schedulingQueryDto.getDeptId());
        qw.eq(User.COL_SCHEDULING_FLAG, Constants.SCHEDULING_FLAG_TRUE);
        qw.eq(User.COL_STATUS, Constants.STATUS_TRUE);
        qw.eq(User.COL_DEL_FLAG, Constants.DEL_FALSE);
        qw.select("user_id", "dept_id", "user_name");
        // 查询需要 排班的医生信息
        return userMapper.selectList(qw);
    }

    /**
     * 查询排班医生的排班信息
     */
    private List<Scheduling> queryScheduling(SchedulingQueryDto schedulingQueryDto) {
        QueryWrapper<Scheduling> qw = new QueryWrapper<>();
        qw.eq(schedulingQueryDto.getUserId() != null, Scheduling.COL_USER_ID, schedulingQueryDto.getUserId());
        qw.eq(schedulingQueryDto.getDeptId() != null, Scheduling.COL_DEPT_ID, schedulingQueryDto.getDeptId());
        qw.ge(schedulingQueryDto.getBeginDate() != null, Scheduling.COL_SCHEDULING_DAY, schedulingQueryDto.getBeginDate());
        qw.le(schedulingQueryDto.getEndDate() != null, Scheduling.COL_SCHEDULING_DAY, schedulingQueryDto.getEndDate());
        return schedulingMapper.selectList(qw);
    }

    /**
     * 获取查询的日期，根据传过来的日期判断是周几 1：表示周日 ； 2：表示周一
     * 如果是周一，那么表示要查询上周的排班，如果是周日，那么表示要查询下周的排班，如果为空，则表示查询本周
     * 获取 当前周的第一天的开始日期 和 结束日期，根据开始时间和结束时间去查询数据库的排班数据
     * 封装对象并返回
     */
    private AjaxResult getSchedulingAjaxResult(SchedulingQueryDto schedulingQueryDto, List<User> users) {
        Date date = DateUtil.date();
        if (StringUtils.isNotBlank(schedulingQueryDto.getQueryDate())) {
            date = DateUtil.parse(schedulingQueryDto.getQueryDate(), "yyyy-MM-dd");
            // 根据传过来的日期判断是周几  1：表示周日 ； 2：表示周一
            int i = DateUtil.dayOfWeek(date);
            if (i == 1) {
                date = DateUtil.offsetDay(date, 1); // 下周一
            } else {
                date = DateUtil.offsetDay(date, -1); // 上周日
            }
        }
        // 获取 当前周的第一天的开始日期 和 结束日期
        DateTime beginTime = DateUtil.beginOfWeek(date);
        DateTime endTime = DateUtil.endOfWeek(date);
        schedulingQueryDto.setBeginDate(DateUtil.format(beginTime, "yyyy-MM-dd"));
        schedulingQueryDto.setEndDate(DateUtil.format(endTime, "yyyy-MM-dd"));
        // 根据开始时间和结束时间去查询数据库的 排班数据
        List<Scheduling> schedulingList = queryScheduling(schedulingQueryDto);
        // 存放页面需要的数据的对象
        List<SchedulingDto> schedulingDtos = new ArrayList<>();
        for (User user : users) { // 循环排班医生数据
            SchedulingDto schedulingDto1 = new SchedulingDto(user.getUserId(), user.getDeptId(), "1", initMap(beginTime));
            SchedulingDto schedulingDto2 = new SchedulingDto(user.getUserId(), user.getDeptId(), "2", initMap(beginTime));
            SchedulingDto schedulingDto3 = new SchedulingDto(user.getUserId(), user.getDeptId(), "3", initMap(beginTime));
            schedulingDtos.add(schedulingDto1);
            schedulingDtos.add(schedulingDto2);
            schedulingDtos.add(schedulingDto3);
            for (Scheduling scheduling : schedulingList) { // 循环排班信息
                Long userId = scheduling.getUserId();
                if (user.getUserId().equals(userId)) {
                    String subsectionType = scheduling.getSubsectionType(); // 排班时间段 1早2中3晚
                    String schedulingDay = scheduling.getSchedulingDay(); // 值班日期
                    switch (subsectionType) {
                        case "1": // 早上 的 排班类型为 门诊或急诊
                            Map<String, String> record1 = schedulingDto1.getRecord();
                            record1.put(schedulingDay, scheduling.getSchedulingType());
                            break;
                        case "2":
                            Map<String, String> record2 = schedulingDto2.getRecord();
                            record2.put(schedulingDay, scheduling.getSchedulingType());
                            break;
                        case "3":
                            Map<String, String> record3 = schedulingDto3.getRecord();
                            record3.put(schedulingDay, scheduling.getSchedulingType());
                            break;
                    }
                }
            }
            // 把 map转成数组数据放到 schedulingType
            schedulingDto1.setSchedulingType(schedulingDto1.getRecord().values());
            schedulingDto2.setSchedulingType(schedulingDto2.getRecord().values());
            schedulingDto3.setSchedulingType(schedulingDto3.getRecord().values());
        }
        // 组装返回的对象
        Map<String, Object> map = new HashMap<>();
        map.put("tableData", schedulingDtos);

        Map<String, Object> schedulingDataMap = new HashMap<>();
        schedulingDataMap.put("startTimeThisWeek", schedulingQueryDto.getBeginDate());
        schedulingDataMap.put("endTimeThisWeek", schedulingQueryDto.getEndDate());

        map.put("schedulingData", schedulingDataMap);
        map.put("labelNames", initLabel(beginTime));
        return AjaxResult.success(map);
    }

    /**
     * 初始化labelNames
     */
    private String[] initLabel(DateTime beginTime) {
        String[] labelNames = new String[7];
        for (int i = 0; i < 7; i++) {
            DateTime dateTime = DateUtil.offsetDay(beginTime, i);
            labelNames[i] = DateUtil.format(dateTime, "yyyy-MM-dd") + formatterWeek(i);
        }
        return labelNames;
    }

    /**
     * 初始化值班记录表（值班日期 是 急诊还是门诊）
     */
    private Map<String, String> initMap(DateTime beginTime) {
        // 按顺序放 2020-08-03 -  2020-08-09
        Map<String, String> map = new TreeMap<>();
        for (int i = 0; i < 7; i++) {
            DateTime dateTime = DateUtil.offsetDay(beginTime, i);
            String key = DateUtil.format(dateTime, "yyyy-MM-dd");
            map.put(key, "");
        }
        return map;
    }

    /**
     * 初始化当前周 周一到周日的日期数组
     */
    private List<String> initSchedulingDay(DateTime beginTime) {
        ArrayList<String> list = new ArrayList<>();
        for (int i = 0; i < 7; i++) {
            list.add(DateUtil.format(DateUtil.offsetDay(beginTime, i), "yyyy-MM-dd"));
        }
        return list;
    }

    /**
     * 翻译周
     */
    private String formatterWeek(int i) {
        switch (i) {
            case 0:
                return "(周一)";
            case 1:
                return "(周二)";
            case 2:
                return "(周三)";
            case 3:
                return "(周四)";
            case 4:
                return "(周五)";
            case 5:
                return "(周六)";
            default:
                return "(周日)";
        }
    }
}
